import tkinter as tk
from tkinter import scrolledtext
import socket
import threading


class TCPClient:
    def __init__(self, root):
        self.root = root
        self.root.title("TCP客户端")
        self.root.geometry("500x500")

        # 连接状态
        self.connected = False
        self.socket = None

        # 创建UI组件
        self.create_widgets()

    def create_widgets(self):
        # 连接信息框架
        frame_conn = tk.LabelFrame(self.root, text="连接信息")
        frame_conn.pack(pady=5, padx=10, fill="x")

        # IP地址
        tk.Label(frame_conn, text="服务器IP:").grid(row=0, column=0, padx=5, pady=5)
        self.entry_ip = tk.Entry(frame_conn)
        self.entry_ip.insert(0, "127.0.0.1")
        self.entry_ip.grid(row=0, column=1, padx=5, pady=5)

        # 端口
        tk.Label(frame_conn, text="端口:").grid(row=0, column=2, padx=5, pady=5)
        self.entry_port = tk.Entry(frame_conn)
        self.entry_port.insert(0, "12345")
        self.entry_port.grid(row=0, column=3, padx=5, pady=5)

        # 连接/断开按钮
        self.btn_connect = tk.Button(frame_conn, text="连接", command=self.toggle_connection)
        self.btn_connect.grid(row=0, column=4, padx=5, pady=5)

        # 消息显示区域
        frame_msg = tk.LabelFrame(self.root, text="消息")
        frame_msg.pack(pady=5, padx=10, fill="both", expand=True)

        self.text_area = scrolledtext.ScrolledText(frame_msg, wrap=tk.WORD)
        self.text_area.pack(pady=5, padx=5, fill="both", expand=True)

        # 消息发送框架
        frame_send = tk.Frame(self.root)
        frame_send.pack(pady=5, padx=10, fill="x")

        self.entry_msg = tk.Entry(frame_send)
        self.entry_msg.pack(side="left", padx=5, pady=5, fill="x", expand=True)

        self.btn_send = tk.Button(frame_send, text="发送", command=self.send_message)
        self.btn_send.pack(side="right", padx=5, pady=5)

        # 绑定回车键发送消息
        self.entry_msg.bind("<Return>", lambda event: self.send_message())

    def toggle_connection(self):
        if not self.connected:
            self.connect_to_server()
        else:
            self.disconnect_from_server()

    def connect_to_server(self):
        ip = self.entry_ip.get()
        port = self.entry_port.get()

        if not ip or not port:
            self.display_message("请输入IP地址和端口号")
            return

        try:
            port = int(port)
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.connect((ip, port))
            self.connected = True
            self.btn_connect.config(text="断开")
            self.display_message(f"已连接到服务器 {ip}:{port}")

            # 启动接收线程
            threading.Thread(target=self.receive_messages, daemon=True).start()
        except Exception as e:
            self.display_message(f"连接失败: {str(e)}")
            if self.socket:
                self.socket.close()
                self.socket = None

    def disconnect_from_server(self):
        if self.socket:
            try:
                self.socket.close()
            except:
                pass
            finally:
                self.socket = None
                self.connected = False
                self.btn_connect.config(text="连接")
                self.display_message("已断开与服务器的连接")

    def send_message(self):
        if not self.connected:
            self.display_message("未连接到服务器")
            return

        msg = self.entry_msg.get()
        if not msg:
            return

        try:
            self.socket.sendall((msg + "\n").encode('utf-8'))  # 添加换行符以便Java服务端readLine读取
            self.display_message(f"发送: {msg}")
            self.entry_msg.delete(0, tk.END)
        except Exception as e:
            self.display_message(f"发送失败: {str(e)}")
            self.disconnect_from_server()

    def receive_messages(self):
        MAX_BUFFER_SIZE = 65536  # 64KB
        buffer = ""
        while self.connected:
            try:
                data = self.socket.recv(1024)
                if not data:
                    break
                buffer += data.decode('utf-8')
                # 防止缓冲区溢出
                if len(buffer) > MAX_BUFFER_SIZE:
                    raise BufferError("接收缓冲区溢出")
                # 按换行符分割消息
                while "\n" in buffer:
                    line, buffer = buffer.split("\n", 1)
                    self.display_message(f"接收: {line}")
            except ConnectionResetError:
                break
            except Exception as e:
                self.display_message(f"接收错误: {str(e)}")
                break

        if self.connected:
            self.root.after(0, self.disconnect_from_server)

    def display_message(self, msg):
        self.text_area.config(state=tk.NORMAL)
        self.text_area.insert(tk.END, msg + "\n")
        self.text_area.config(state=tk.DISABLED)
        self.text_area.see(tk.END)

    def on_closing(self):
        self.disconnect_from_server()
        self.root.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    client = TCPClient(root)
    root.protocol("WM_DELETE_WINDOW", client.on_closing)
    root.mainloop()